package list

type Element struct {
	prev, next *Element
	list       *List
	Value      interface{}
}

type List struct {
	root Element
	len  int
}

func (o *Element) Next() *Element {
	if o.next == &o.list.root {
		return nil
	}
	return o.next
}

func (o *Element) Prev() *Element {
	if o.prev == &o.list.root {
		return nil
	}
	return o.prev
}

func (o *List) Len() int {
	return o.len
}

func (o *List) init() *List {
	o.root.next = &o.root
	o.root.prev = &o.root
	return o
}

func New() *List {
	return new(List).init()
}

func (o *List) insert(e, at *Element) *Element {
	e.prev = at
	e.next = at.next
	e.next.prev = e
	e.prev.next = e

	e.list = o
	o.len++
	return e
}

func (o *List) insertValue(v interface{}, at *Element) *Element {
	return o.insert(&Element{Value: v}, at)
}

func (o *List) lazyInit() {
	if o.root.next == nil {
		o.root.next = &o.root
		o.root.prev = &o.root
	}
}

func (o *List) PushBack(v interface{}) *Element {
	o.lazyInit()
	return o.insertValue(v, o.root.prev)
}

func (o *List) remove(e *Element) *Element {
	e.prev.next = e.next
	e.next.prev = e.prev

	e.next = nil
	e.prev = nil
	e.list = nil
	o.len--
	return e
}

func (o *List) Remove(e *Element) interface{} {
	if e.list == o {
		o.remove(e)
	}
	return e.Value
}

func (o *List) Front() *Element {
	if o.len == 0 {
		return nil
	}
	return o.root.next
}
